package com.xframe.xdal.core.handler;

import com.xframe.xdal.core.autofill.AutoProcRuntime;
import com.xframe.xdal.core.constant.DataSourceTypeEnums;
import com.xframe.xdal.core.constant.RunOpportunity;
import com.xframe.xdal.core.model.mapping.ITableInfo;
import com.xframe.xdal.core.util.ModelUtil;
import com.xframe.xdal.core.util.StringUtil;
import com.xframe.xdal.core.util.XReflect;
import lombok.extern.log4j.Log4j2;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

/**
 * 功能描述: 映射帮助对象集合管理器
 *
 * @author xufeng
 * @version 1.0
 * @date 2023-03-20
 */
@Log4j2
public class HandlerColumnMapManage {

    /**
     * select 语句映射的数据结构
     */
    private Map<Integer, HandlerColumn> handlerColumnMap = new HashMap<>();


    private Object bean;
    private ITableInfo mainTableInfo;
    private Object cloneBean = null;
    private boolean isInitCloneBean = false;

    private Map<String, ITableInfo> refTableInfoMap = new HashMap<>();
    private Map<String,Object> refMap = new HashMap<>();

    private Map<String,InnerDataStruct> refListMap = new HashMap<>();

    private DataSourceTypeEnums dataSourceTypeEnums;

    // 0 = 当前行 1 = 重复的行
    private int curStatus = 0;


    public int size(){
        return this.handlerColumnMap.size();
    }

    public HandlerColumnMapManage(DataSourceTypeEnums dataSourceTypeEnums){
        this.dataSourceTypeEnums = dataSourceTypeEnums;
    }

    public void setMainTableInfo(ITableInfo tableInfo){
        this.mainTableInfo = tableInfo;
    }

    /**
     * 设置当前对象
     */
    public void setBean(Object bean) {
        this.bean = bean;
    }
    /**
     * 处理新行的映射
     */
    public void setValueStrategy(Object value,int colIndex){
        curStatus = 0;
        HandlerColumn handlerColumn = get(colIndex);
        // 如果不是应用字段 也不是 引用子表
        if(!handlerColumn.isRefFlag() && !handlerColumn.isRefListFlag()){
            // 直接对本对象设置值
            XReflect.setFieldValue(bean,handlerColumn.getColumnMapping().getFieldName(),value);
        }
        if(handlerColumn.isRefFlag()){
            // 引用列
            if(!refMap.containsKey(handlerColumn.getRefPathName())){

                Object refObject = XReflect.getFieldValueByInit(bean,handlerColumn.getRefPathName());
                refMap.put(handlerColumn.getRefPathName(),refObject);
                refTableInfoMap.put(handlerColumn.getRefPathName(),handlerColumn.getRefTableInfo());
            }
            XReflect.setFieldValue(refMap.get(handlerColumn.getRefPathName()),handlerColumn.getColumnMapping().getFieldName(),value);
        }
        if(handlerColumn.isRefListFlag()){
            // 子列表处理
            if(!refListMap.containsKey(handlerColumn.getRefPathName())){
                // 初始化列表
                initList(handlerColumn);
                initCurListBean(handlerColumn,value);
            }
            XReflect.setFieldValue(refListMap.get(handlerColumn.getRefPathName()).curlisBean,
                    handlerColumn.getColumnMapping().getFieldName(),value);

        }

    }

    /**
     * 处理重复行(引用子表)的映射
     */
    public void setValueListStrategy(ResultSet resultSet,int colIndex){
        curStatus = 1;
        HandlerColumn handlerColumn = get(colIndex);

        if(handlerColumn.isRefListFlag()){
            Object value = getValueTaking(resultSet,colIndex);

            InnerDataStruct dataStruct = refListMap.get(handlerColumn.getRefPathName());
            if(dataStruct != null && !dataStruct.isShipLine) {
                if (dataStruct.curlisBean == null) {
                    initCurListBeanByRepeat(handlerColumn,value);
                }
                if(dataStruct.curlisBean != null) {
                    XReflect.setFieldValue(dataStruct.curlisBean,
                            handlerColumn.getColumnMapping().getFieldName(), value);
                }
            }
        }
    }

    private void initCurListBeanByRepeat(HandlerColumn handlerColumn,Object value){
        try {
            InnerDataStruct dataStruct = refListMap.get(handlerColumn.getRefPathName());
            if(!dataStruct.lastValue.containsKey(value)) {
                dataStruct.curlisBean = handlerColumn.getDataType().newInstance();
                Method m = dataStruct.lis.getClass().getMethod("add", Object.class);
                m.invoke(dataStruct.lis, dataStruct.curlisBean);
                dataStruct.lastValue.put(value,value);
                setRefModel(handlerColumn,dataStruct.curlisBean);
            }else {
                dataStruct.isShipLine = true;
            }
        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private void initCurListBean(HandlerColumn handlerColumn,Object value){
        try {
            InnerDataStruct dataStruct = refListMap.get(handlerColumn.getRefPathName());
            dataStruct.curlisBean = handlerColumn.getDataType().newInstance();
            dataStruct.lastValue.put(value,value);
            Method m = dataStruct.lis.getClass().getMethod("add", Object.class);
            m.invoke(dataStruct.lis, dataStruct.curlisBean);

            setRefModel(handlerColumn,dataStruct.curlisBean);

        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private void setRefModel(HandlerColumn handlerColumn,Object curlisBean){
        if(handlerColumn.getRelation() != null && !StringUtil.isEmpty(handlerColumn.getRelation().getRefName())){
            Field field = XReflect.getAccessibleField(curlisBean,handlerColumn.getRelation().getRefName());
            if(field != null){
                //if(field.getType().equals(this.bean.getClass())){
                    try {
                        field.set(curlisBean,this.getCloneBean(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                //}
            }
        }
    }

    private Object getCloneBean(Class<?> dataType){
        if(!isInitCloneBean) {
            cloneBean = ModelUtil.cloneByTableInfo(this.bean,dataType, this.mainTableInfo);
            isInitCloneBean = true;
        }
        return cloneBean;
    }

    private void initList(HandlerColumn handlerColumn){
        try {
            Object lis = Class.forName("java.util.ArrayList").newInstance();
            InnerDataStruct dataStruct = new InnerDataStruct();
            dataStruct.lis = lis;
            refListMap.put(handlerColumn.getRefPathName(),dataStruct);
            refTableInfoMap.put(handlerColumn.getRefPathName(),handlerColumn.getRefTableInfo());
            XReflect.setFieldValue(bean,handlerColumn.getRefPathName(),lis);
        }catch (Exception ex){
            log.info(ex.getMessage());
        }
    }



    public void put(Integer colIndex,HandlerColumn handlerColumn){
        this.handlerColumnMap.put(colIndex,handlerColumn);
    }
    public HandlerColumn get(Integer colIndex){
        return this.handlerColumnMap.get(colIndex);
    }
    public boolean containsKey(Integer colIndex){
        return this.handlerColumnMap.containsKey(colIndex);
    }

    /**
     * 新的一行映射的开始，全新的主对象
     *
     */
    public void init(){
        this.bean = null;
        this.refMap = new HashMap<>();
        this.refListMap = new HashMap<>();
        this.refTableInfoMap = new HashMap<>();
    }

    /**
     * 一行映射结束后
     *
     * @param autoProcRuntime  自动映射对象
     *
     * @return
     */
    public void setLineEnd(AutoProcRuntime autoProcRuntime){

        if(curStatus == 0){
            // 需要处理引用对象的自动填充
            for (Map.Entry<String, Object> entry : refMap.entrySet()) {
                ITableInfo tableInfo = this.refTableInfoMap.get(entry.getKey());
                if(tableInfo != null) {
                    autoProcRuntime.autoFill(entry.getValue(), tableInfo, RunOpportunity.R);
                }
            }
        }
        for (Map.Entry<String, InnerDataStruct> entry : refListMap.entrySet()) {
            if(!entry.getValue().isShipLine && entry.getValue().curlisBean != null){
                ITableInfo tableInfo = this.refTableInfoMap.get(entry.getKey());
                if(tableInfo != null) {
                    autoProcRuntime.autoFill(entry.getValue().curlisBean, tableInfo, RunOpportunity.R);
                }
            }
            entry.getValue().curlisBean = null;
            entry.getValue().isShipLine = false;
        }
    }

    /**
     * 获得ResultSet对象的值
     *
     * @param resultSet resultSet对象
     * @param colIndex 下标
     */
    public Object getValueTaking(ResultSet resultSet, Integer colIndex){
        Object val = get(colIndex).getValueTakingStrategy(this.dataSourceTypeEnums).getValue(resultSet,colIndex);
        return val;
    }


    static class InnerDataStruct{
        public Object lis;
        public Object curlisBean;
        public Map<Object,Object> lastValue = new HashMap<>();
        public boolean isShipLine;
    }

}


